package weka.core.converters;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import weka.core.Attribute;
import weka.core.DenseInstance;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.converters.interfaces.AuditTrailEntry;
import weka.core.converters.interfaces.ProcessInstance;
import weka.core.converters.interfaces.VarData;
import weka.core.converters.interfaces.WorkflowLog;


public class MXMLLoader extends AbstractFileLoader {
	
	private String eventType="EventType";
	private String originator="Originator";
	private String timeStamp="TimeStamp";
	private String workflowModelElement="WorkflowModelElement";
	private List<ProcessInstance> instances;
	private Vector<String> users;
	private Vector<VarData> eventTypes = new Vector<VarData>();
	private Vector<VarData> originators = new Vector<VarData>();
	private Vector<VarData> timestamps = new Vector<VarData>();
	private Vector<VarData> wfelements = new Vector<VarData>();
	private Instances wekaInstances;
	
	
	private static String FILE_EXTENSION = ".mxml";
	
	public MXMLLoader() {
		// TODO Auto-generated constructor stub
	}
	
	public void loadWorkFlow(String path){
		eventTypes = new Vector<VarData>();
		originators = new Vector<VarData>();
		timestamps = new Vector<VarData>();
		wfelements = new Vector<VarData>();
		JAXBContext context;
		try {
		try {
			context = JAXBContext.newInstance("weka.core.converters.interfaces");
			Unmarshaller unmarshaller = context.createUnmarshaller(); 
			WorkflowLog process = (WorkflowLog) unmarshaller.unmarshal(new FileInputStream(path));
			this.instances = process.getProcess().getProcessInstance();
			this.loadVariables(process.getProcess().getProcessInstance());
		} catch (JAXBException e1) {
			e1.printStackTrace();
		}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} 
	}
	
	public void loadVariables(List<ProcessInstance> name){
		this.users = new Vector<String>();
		for (ProcessInstance instance : name) {
			for (AuditTrailEntry entry :  instance.getAuditTrailEntry()){
				this.addOcurrency(eventTypes, entry.getEventType(),eventType);
				this.addOcurrency(originators, entry.getOriginator(),originator);
				if (!users.contains(entry.getOriginator())){
					users.add(entry.getOriginator());
				}
				this.addOcurrency(timestamps, entry.getTimestamp().toString(),timeStamp);
				this.addOcurrency(wfelements, entry.getWorkflowModelElement(),workflowModelElement);
			}
		}		
		
		ArrayList<Attribute> aList = new ArrayList<Attribute>();
		for(VarData var : this.wfelements){
			aList.add(new Attribute(var.getValue()+"_originator",getList(originators)));
			aList.add(new Attribute(var.getValue()+"_timeStamp",getList(timestamps)));
			aList.add(new Attribute(var.getValue()+"_eventType",getList(eventTypes)));
		}
		wekaInstances = new Instances("Workflow Relation", aList, 9999);
		this.loadInstances(name);
	}
		
	
	public void loadInstances(List<ProcessInstance> name){
		Map<String,Double> originatorsMap = new HashMap<String, Double>();
		Map<String,Double> timestampMap = new HashMap<String, Double>();
		Map<String,Double> eventTypeMap = new HashMap<String, Double>();
 		Double value=0.0;
		for(VarData var : this.originators){
			originatorsMap.put(var.getValue(),value);
			value+=1.0;
		}
		value=0.0;
		for(VarData var : this.timestamps){
			timestampMap.put(var.getValue(),value);
			value+=1.0;
		}
		value=0.0;
		for(VarData var : this.eventTypes){
			eventTypeMap.put(var.getValue(),value);
			value+=1.0;
		}
		Instance wekaInstance;
		double[] attValues = new double[9999];
		for (ProcessInstance instance : name) {
			for (AuditTrailEntry entry :  instance.getAuditTrailEntry()){
				attValues[0]=originatorsMap.get(entry.getOriginator());
				attValues[1]=timestampMap.get(entry.getTimestamp().toString());
				attValues[2]=eventTypeMap.get(entry.getEventType());
				wekaInstance = new DenseInstance(1.0, attValues);
				wekaInstances.add(wekaInstance);
			}
		}
	}
	
	public List<String> getList(Vector<VarData> vector){
		List<String> list = new ArrayList<String>();
		for (VarData varData : vector) {
			list.add(varData.getValue());
		}
		return list;
	}
	
	public void addOcurrency(Vector<VarData> vector,String value,String name){
		for (VarData data : vector) {
			if (data.getValue().equals(value)){
				data.setOcurrencies(data.getOcurrencies()+1);
				return;
			}
		}
		VarData newData = new VarData(name,value);
		vector.add(newData);
	}

	@Override
	public String getFileExtension() {
		return FILE_EXTENSION;
	}

	@Override
	public String[] getFileExtensions() {
		return new String[]{FILE_EXTENSION};
	}

	@Override
	public String getFileDescription() {
		return ".MXML workflow data files";
	}

	@Override
	public String getRevision() {
		return "";
	}

	@Override
	public Instances getStructure() throws IOException {
		return wekaInstances;
	}

	@Override
	public Instances getDataSet() throws IOException {
		return wekaInstances;
	}

	@Override
	public Instance getNextInstance(Instances structure) throws IOException {
		Instance instance;
		return null;
	}

	/**
	 * sets the source File
	 * 
	 * @param file
	 *            the source file
	 * @throws IOException
	 *             if an error occurs
	 */
	public void setFile(File file) throws IOException {
		this.loadWorkFlow(file.getPath());
	}
}
